home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / ghostscript / src / gdevwdib.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  12KB  |  424 lines

  1. /* Copyright (C) 1992, 1993 Aladdin Enterprises.  All rights reserved.
  2.  
  3. This file is part of Ghostscript.
  4.  
  5. Ghostscript is distributed in the hope that it will be useful, but
  6. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  7. to anyone for the consequences of using it or for whether it serves any
  8. particular purpose or works at all, unless he says so in writing.  Refer
  9. to the Ghostscript General Public License for full details.
  10.  
  11. Everyone is granted permission to copy, modify and redistribute
  12. Ghostscript, but only under the conditions described in the Ghostscript
  13. General Public License.  A copy of this license is supposed to have been
  14. given to you along with Ghostscript so you can know your rights and
  15. responsibilities.  It should be in a file named COPYING.  Among other
  16. things, the copyright notice and this notice must be preserved on all
  17. copies.  */
  18.  
  19. /* gdevwdib.c */
  20. /* MS Windows 3.n driver for Ghostscript using a DIB for buffering. */
  21. #include "dos_.h"
  22. #include "gdevmswn.h"
  23. #include "gxdevmem.h"
  24.  
  25. /* Make sure we cast to the correct structure type. */
  26. typedef struct gx_device_win_dib_s gx_device_win_dib;
  27. #undef wdev
  28. #define wdev ((gx_device_win_dib *)dev)
  29.  
  30. /* Device procedures */
  31.  
  32. /* See gxdevice.h for the definitions of the procedures. */
  33. private dev_proc_open_device(win_dib_open);
  34. private dev_proc_get_initial_matrix(win_dib_get_initial_matrix);
  35. private dev_proc_close_device(win_dib_close);
  36. private dev_proc_map_rgb_color(win_dib_map_rgb_color);
  37. private dev_proc_fill_rectangle(win_dib_fill_rectangle);
  38. private dev_proc_copy_mono(win_dib_copy_mono);
  39. private dev_proc_copy_color(win_dib_copy_color);
  40. /* Windows-specific procedures */
  41. private win_proc_copy_to_clipboard(win_dib_copy_to_clipboard);
  42. private win_proc_repaint(win_dib_repaint);
  43. private win_proc_alloc_bitmap(win_dib_alloc_bitmap);
  44. private win_proc_free_bitmap(win_dib_free_bitmap);
  45.  
  46. /* The device descriptor */
  47. struct gx_device_win_dib_s {
  48.     gx_device_common;
  49.     gx_device_win_common;
  50.  
  51.     /* The following help manage the division of the DIB */
  52.     /* into 64K segments.  Each block of y_block scan lines */
  53.     /* starting at y_base mod 64K falls in a single segment. */
  54.     /* Since the raster is a power of 2, y_block is a power of 2. */
  55.  
  56.     int y_block;
  57.     int y_base;
  58.     int y_mask;        /* y_block - 1 */
  59.  
  60.     HGLOBAL hmdata;
  61.     gx_device_memory mdev;
  62. };
  63. private gx_device_procs win_dib_procs = {
  64.     win_dib_open,
  65.     win_dib_get_initial_matrix,
  66.     win_sync_output,
  67.     win_output_page,
  68.     win_dib_close,
  69.     win_dib_map_rgb_color,
  70.     win_map_color_rgb,
  71.     win_dib_fill_rectangle,
  72.     gx_default_tile_rectangle,
  73.     win_dib_copy_mono,
  74.     win_dib_copy_color,
  75.     gx_default_draw_line,
  76.     gx_default_get_bits,
  77.     gx_default_get_props,
  78.     win_put_props,
  79.     gx_default_map_cmyk_color,
  80.     win_get_xfont_procs
  81. };
  82. gx_device_win_dib gs_mswin_device = {
  83.     sizeof(gx_device_win_dib),
  84.     &win_dib_procs,
  85.     "mswin",
  86.     INITIAL_WIDTH, INITIAL_HEIGHT,     /* win_open() fills these in later */
  87.     INITIAL_RESOLUTION, INITIAL_RESOLUTION,    /* win_open() fills these in later */
  88.     no_margins,
  89.     dci_black_and_white,
  90.     0,        /* not open yet */
  91.     2,        /* nColors */
  92.     win_dib_copy_to_clipboard,
  93.     win_dib_repaint,
  94.     win_dib_alloc_bitmap,
  95.     win_dib_free_bitmap
  96. };
  97.  
  98.  
  99. /* Open the win_dib driver */
  100. private int
  101. win_dib_open(gx_device *dev)
  102. {
  103.     int code = win_open(dev);
  104.     if ( code < 0 ) return code;
  105.  
  106.     if ( gdev_mem_device_for_bits(dev->color_info.depth) == 0 )
  107.     {    win_close(dev);
  108.         return gs_error_rangecheck;
  109.     }
  110.     return win_dib_alloc_bitmap((gx_device_win *)dev, dev);
  111. }
  112.  
  113. /* Get the initial matrix.  DIBs, unlike most displays, */
  114. /* put (0,0) in the lower left corner. */
  115. private void
  116. win_dib_get_initial_matrix(gx_device *dev, gs_matrix *pmat)
  117. {    pmat->xx = dev->x_pixels_per_inch / 72.0;
  118.     pmat->xy = 0;
  119.     pmat->yx = 0;
  120.     pmat->yy = dev->y_pixels_per_inch / 72.0;
  121.     pmat->tx = 0;
  122.     pmat->ty = 0;
  123. }
  124.  
  125. /* Close the win_dib driver */
  126. private int
  127. win_dib_close(gx_device *dev)
  128. {    win_dib_free_bitmap((gx_device_win *)dev);
  129.     return win_close(dev);
  130. }
  131.  
  132. /* Map a r-g-b color to the colors available under Windows */
  133. private gx_color_index
  134. win_dib_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g,
  135.   gx_color_value b)
  136. {    int i = wdev->nColors;
  137.     gx_color_index color = win_map_rgb_color(dev, r, g, b);
  138.     if ( color != i ) return color;
  139.  
  140.     return color;
  141. }
  142.  
  143. /* The drawing routines must all be careful not to cross */
  144. /* a segment boundary. */
  145.  
  146. #define wmdev ((gx_device *)&wdev->mdev)
  147. #define wmproc(proc) (*wdev->mdev.procs->proc)
  148.  
  149. #define single_block(y, h)\
  150.   !(((y - wdev->y_base) ^ (y - wdev->y_base + h - 1)) & ~wdev->y_mask)
  151.  
  152. #define BEGIN_BLOCKS\
  153. {    int by, bh, left = h;\
  154.     for ( by = y; left > 0; by += bh, left -= bh )\
  155.     {    bh = wdev->y_block - (by & wdev->y_mask);\
  156.         if ( bh > left ) bh = left;
  157. #define END_BLOCKS\
  158.     }\
  159. }
  160.  
  161. /* Fill a rectangle. */
  162. private int
  163. win_dib_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
  164.   gx_color_index color)
  165. {    if ( single_block(y, h) )
  166.     {    wmproc(fill_rectangle)(wmdev, x, y, w, h, color);
  167.     }
  168.     else
  169.     {    /* Divide the transfer into blocks. */
  170.         BEGIN_BLOCKS
  171.             wmproc(fill_rectangle)(wmdev, x, by, w, bh, color);
  172.         END_BLOCKS
  173.     }
  174.     win_update((gx_device_win *)dev);
  175.     return 0;
  176. }
  177.  
  178. /* Copy a monochrome bitmap.  The colors are given explicitly. */
  179. /* Color = gx_no_color_index means transparent (no effect on the image). */
  180. private int
  181. win_dib_copy_mono(gx_device *dev,
  182.   const byte *base, int sourcex, int raster, gx_bitmap_id id,
  183.   int x, int y, int w, int h,
  184.   gx_color_index zero, gx_color_index one)
  185. {    if ( single_block(y, h) )
  186.     {    wmproc(copy_mono)(wmdev, base, sourcex, raster, id,
  187.                      x, y, w, h, zero, one);
  188.     }
  189.     else
  190.     {    /* Divide the transfer into blocks. */
  191.         const byte *source = base;
  192.         BEGIN_BLOCKS
  193.             wmproc(copy_mono)(wmdev, source, sourcex, raster,
  194.                       gx_no_bitmap_id, x, by, w, bh,
  195.                       zero, one);
  196.             source += bh * raster;
  197.         END_BLOCKS
  198.     }
  199.     win_update((gx_device_win *)dev);
  200.     return 0;
  201. }
  202.  
  203. /* Copy a color pixel map.  This is just like a bitmap, except that */
  204. /* each pixel takes 8 or 4 bits instead of 1 when device driver has color. */
  205. private int
  206. win_dib_copy_color(gx_device *dev,
  207.   const byte *base, int sourcex, int raster, gx_bitmap_id id,
  208.   int x, int y, int w, int h)
  209. {    if ( single_block(y, h) )
  210.     {    wmproc(copy_color)(wmdev, base, sourcex, raster, id,
  211.                       x, y, w, h);
  212.     }
  213.     else
  214.     {    /* Divide the transfer into blocks. */
  215.         const byte *source = base;
  216.         BEGIN_BLOCKS
  217.             wmproc(copy_color)(wmdev, source, sourcex, raster,
  218.                        gx_no_bitmap_id, x, by, w, bh);
  219.             source += by * raster;
  220.         END_BLOCKS
  221.     }
  222.     win_update((gx_device_win *)dev);
  223.     return 0;
  224. }
  225.  
  226. /* ------ Windows-specific device procedures ------ */
  227.  
  228.  
  229. /* Repaint a section of the window. */
  230. private void
  231. win_dib_repaint(gx_device_win *dev, HDC hdc, int dx, int dy, int wx, int wy,
  232.   int sx, int sy)
  233. {    struct bmi_s {
  234.         BITMAPINFOHEADER h;
  235.         ushort pal_index[256];
  236.     } bmi;
  237.     int i;
  238.  
  239.     bmi.h.biSize = sizeof(bmi.h);
  240.     bmi.h.biWidth = wdev->mdev.width;
  241.     bmi.h.biHeight = wy;
  242.     bmi.h.biPlanes = 1;
  243.     bmi.h.biBitCount = dev->color_info.depth;
  244.     bmi.h.biCompression = 0;
  245.     bmi.h.biSizeImage = 0;            /* default */
  246.     bmi.h.biXPelsPerMeter = 0;        /* default */
  247.     bmi.h.biYPelsPerMeter = 0;        /* default */
  248.     bmi.h.biClrUsed = wdev->nColors;
  249.     bmi.h.biClrImportant = wdev->nColors;
  250.     for ( i = 0; i < wdev->nColors; i++ )
  251.         bmi.pal_index[i] = i;
  252.  
  253.     SetDIBitsToDevice(hdc, dx, dy, wx, wy,
  254.         sx, 0, 0, wy,
  255.         wdev->mdev.line_ptrs[wdev->height - (sy + wy)],
  256.         (BITMAPINFO FAR *)&bmi, DIB_PAL_COLORS);
  257. }
  258.  
  259.  
  260. /* This makes a DIB that contains all or part of the bitmap. */
  261. /* The bitmap pixel orgx must start on a byte boundary. */
  262. private HGLOBAL
  263. win_dib_make_dib(gx_device_win *dev, int orgx, int orgy, int wx, int wy)
  264. {
  265. #define xwdev ((gx_device_win_dib *)dev)
  266.     gx_color_value prgb[3];
  267.     HGLOBAL hglobal;
  268.     BYTE FAR *pDIB;
  269.     BITMAPINFOHEADER FAR *pbmih;
  270.     RGBQUAD FAR *pColors;
  271.     BYTE huge *pBits;
  272.     BYTE huge *pLine;
  273.     ulong bitmapsize;
  274.     int i;
  275.     int loffset;         /* byte offset to start of line */
  276.     UINT lwidth;        /* line width in bytes rounded up to multiple of 4 bytes */
  277.     UINT lseg;        /* bytes remaining in this segment */
  278.  
  279.     if (orgx + wx > wdev->width)
  280.         wx = wdev->width - orgx;
  281.     if (orgy + wy > wdev->height)
  282.         wy = wdev->height - orgy;
  283.  
  284.     loffset = orgx * wdev->color_info.depth / 8;
  285.     lwidth =  ((wx * wdev->color_info.depth + 31) & ~31) >> 3;
  286.     bitmapsize = (long)lwidth * wy;
  287.  
  288.     hglobal = GlobalAlloc(GHND | GMEM_SHARE, sizeof(BITMAPINFOHEADER) 
  289.         + sizeof(RGBQUAD)*wdev->nColors + bitmapsize);
  290.     if (hglobal == (HGLOBAL)NULL) {
  291.         MessageBeep(-1);
  292.         return(HGLOBAL)NULL;
  293.     }
  294.     pDIB = (BYTE FAR *)GlobalLock(hglobal);
  295.     if (pDIB == (BYTE FAR *)NULL) {
  296.         MessageBeep(-1);
  297.         return(HGLOBAL)NULL;
  298.     }
  299.     pbmih = (BITMAPINFOHEADER FAR *)(pDIB); 
  300.     pColors = (RGBQUAD FAR *)(pDIB + sizeof(BITMAPINFOHEADER));
  301.     pBits = (BYTE huge *)(pDIB + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*wdev->nColors);
  302.  
  303.     pbmih->biSize = sizeof(BITMAPINFOHEADER);
  304.     pbmih->biWidth = wx;
  305.     pbmih->biHeight = wy;
  306.     pbmih->biPlanes = 1;
  307.     pbmih->biBitCount = wdev->color_info.depth;
  308.     pbmih->biCompression = 0;
  309.     pbmih->biSizeImage = 0;            /* default */
  310.     pbmih->biXPelsPerMeter = 0;        /* default */
  311.     pbmih->biYPelsPerMeter = 0;        /* default */
  312.     pbmih->biClrUsed = wdev->nColors;
  313.     pbmih->biClrImportant = wdev->nColors;
  314.  
  315.     for ( i = 0; i < wdev->nColors; i++ ) {
  316.         win_map_color_rgb((gx_device *)wdev, (gx_color_index)i, prgb);
  317.         pColors[i].rgbRed   = win_color_value(prgb[0]);
  318.         pColors[i].rgbGreen = win_color_value(prgb[1]);
  319.         pColors[i].rgbBlue  = win_color_value(prgb[2]);
  320.         pColors[i].rgbReserved = 0;
  321.     }
  322.  
  323.  
  324.     pLine = pBits;
  325.     for ( i = orgy; i < orgy + wy; i++ ) {
  326.         /* Window 3.1 has hmemcpy, but 3.0 doesn't */
  327.         lseg = (UINT)(-OFFSETOF(pLine));   /* remaining bytes in this segment */
  328.         if (lseg >= lwidth) { 
  329.            _fmemcpy(pLine, xwdev->mdev.line_ptrs[i] + loffset, lwidth);
  330.         }
  331.             else { /* break up transfer to avoid crossing segment boundary */
  332.            _fmemcpy(pLine, xwdev->mdev.line_ptrs[i] + loffset, lseg);
  333.            _fmemcpy(pLine+lseg, xwdev->mdev.line_ptrs[i] + loffset + lseg, lwidth - lseg);
  334.         }
  335.         pLine += lwidth;
  336.     }
  337.  
  338.     GlobalUnlock(hglobal);
  339.     return hglobal;
  340. }
  341.  
  342.  
  343. /* Copy the bitmap to the clipboard. */
  344. private void
  345. win_dib_copy_to_clipboard(gx_device_win *dev)
  346. {
  347.     HGLOBAL hglobal;
  348.     hglobal = win_dib_make_dib(dev, 0, 0, wdev->width, wdev->height);
  349.     if (hglobal == (HGLOBAL)NULL) {
  350.         MessageBox(wdev->hwndimg, "Not enough memory to Copy to Clipboard", 
  351.         szAppName, MB_OK | MB_ICONEXCLAMATION);
  352.         return;
  353.     }
  354.     OpenClipboard(dev->hwndimg);
  355.     EmptyClipboard();
  356.     SetClipboardData(CF_DIB, hglobal);
  357.     SetClipboardData(CF_PALETTE, CreatePalette(wdev->limgpalette));
  358.     CloseClipboard();
  359. }
  360.  
  361.  
  362. /* Allocate the backing bitmap. */
  363. private int
  364. win_dib_alloc_bitmap(gx_device_win *dev, gx_device *param_dev)
  365. {
  366.     int width;
  367.     gx_device_memory mdev;
  368.     HGLOBAL hmdata;
  369.     byte huge *base;
  370.     byte huge *ptr_base;
  371.     ulong data_size;
  372.     uint ptr_size;
  373.     uint raster;
  374.  
  375.     /* Round up the width so that the scan line size is a power of 2. */
  376.     /* Only works if bits per pixel is a power of 2, i.e., */
  377.     /* doesn't work for 24-bit devices.  We'll fix this someday.... */
  378.  
  379.     width = param_dev->width - 1;
  380.     while ( width & (width + 1) ) width |= width >> 1;
  381.     width++;
  382.  
  383.     /* Finish initializing the DIB. */
  384.  
  385.     mdev = *gdev_mem_device_for_bits(dev->color_info.depth);
  386.     mdev.width = width;
  387.     mdev.height = param_dev->height;
  388.     mdev.target = (gx_device *)dev;
  389.     raster = gdev_mem_raster(&mdev);
  390.     data_size = (ulong)raster * mdev.height;
  391.     ptr_size = sizeof(byte **) * mdev.height;
  392.     hmdata = GlobalAlloc(0, raster + data_size + ptr_size * 2);
  393.     if ( hmdata == 0 )
  394.         return win_nomemory();
  395.  
  396.     /* Nothing can go wrong now.... */
  397.  
  398.     wdev->hmdata = hmdata;
  399.     base = GlobalLock(hmdata);
  400.     /* Adjust base so scan lines, and the pointer table, */
  401.     /* don't cross a segment boundary. */
  402.     base += (-PTR_OFF(base) & (raster - 1));
  403.     ptr_base = base + data_size;
  404.     if ( PTR_OFF(ptr_base + ptr_size) < ptr_size )
  405.         base += (uint)-PTR_OFF(ptr_base);
  406.     wdev->mdev = mdev;
  407.     wdev->mdev.base = (byte *)base;
  408.     wdev->y_block = 0x10000L / raster;
  409.     wdev->y_mask = wdev->y_block - 1;
  410.     if ( (wdev->y_base = PTR_OFF(base)) != 0 )
  411.         wdev->y_base = -(PTR_OFF(base) / raster);
  412.     (*wdev->mdev.procs->open_device)((gx_device *)&wdev->mdev);
  413.     return 0;
  414. }
  415.  
  416.  
  417. /* Free the backing bitmap. */
  418. private void
  419. win_dib_free_bitmap(gx_device_win *dev)
  420. {    HGLOBAL hmdata = wdev->hmdata;
  421.     GlobalUnlock(hmdata);
  422.     GlobalFree(hmdata);
  423. }
  424.